<?php

namespace app\common\service\trainer;


use app\common\enums\CourseDeliveryTypeEnum;
use app\common\enums\TrainerSalaryProjectEnum;
use app\common\model\banxi\core\CoreTrainerMonthSalary as CoreTrainerMonthSalaryModel;
use app\common\model\banxi\core\CoreTrainerMonthSalaryDetail as CoreTrainerMonthSalaryDetailModel;
use app\common\model\banxi\core\CoreTrainerSalary;
use app\common\service\ApiService;
use app\common\service\SnowflakeService;
use ba\Exception;
use think\db\exception\PDOException;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Db;

class TrainerSalaryService extends ApiService
{

    public function createSalary($salary)
    {
        $id = $salary['id'] ?? null;
        $coreTrainerSalaryModel = new CoreTrainerSalary();
        if ($id) {
            $oreTrainerSalaryInfo = $coreTrainerSalaryModel->where('id', $id)->find();
            if (!$oreTrainerSalaryInfo) {
                $this->setError('记录不存在');
                return false;
            }
            $oreTrainerSalaryInfo->save($salary);
        } else {
            try {
                $coreTrainerSalaryModel->createSalary($salary);
                $res = $this->createMonthSalary($salary);
                if (!$res) {
                    throw new ValidateException($this->getError());
                }
            } catch (Exception|PDOException|ValidateException $e) {
                $this->setError($e->getMessage());
                return false;
            }
        }
        return true;
    }

    private function createMonthSalary($salary)
    {
        $month = date('Y-m');
        $trainerId = $salary['trainerId'];
        $coreTrainerMonthSalaryModel = new CoreTrainerMonthSalaryModel();
        $trainerMonthSalary = $coreTrainerMonthSalaryModel->getByTrainerAndMonth($trainerId, $month);
        if ($trainerMonthSalary) {
            return $trainerMonthSalary;
        }
        $baseSalary = $salary['baseSalary'];
        $key = "CoreTrainerSalary:createMonthSalary:" . $trainerId . ":" . $month;
        if (Cache::has($key)) {
            throw new ValidateException('教练正在创建当月工资中，请稍后重试');
        }
        Cache::set($key, 1, 30);
        Db::startTrans();
        try {
            $snowflakeService = new SnowflakeService(1, 1);
            $trainerMonthSalary = [
                'id' => $snowflakeService->nextId(),
                'trainerId' => $trainerId,
                'month' => $month,
                'totalAmount' => $baseSalary,
                'class30Num' => 0,
                'class60Num' => 0,
                'classTrialNum' => 0,
                'antiNum' => 0,
                'teachingOnlineNum' => 0,
                'teachingOrganizationNum' => 0,
                'teachingVisitNum' => 0
            ];
            $coreTrainerMonthSalaryModel->save($trainerMonthSalary);
            $project = TrainerSalaryProjectEnum::BASIC;
            $monthSalaryDetailModel = new CoreTrainerMonthSalaryDetailModel();
            $trainerMonthSalaryDetail = [
                'trainerId' => $trainerId,
                'monthSalaryId' => $trainerMonthSalary['id'],
                'month' => $month,
                'describe' => (new TrainerSalaryProjectEnum)->getDescription($project),
                'project' => $project,
                'num' => 1,
                'price' => $baseSalary,
                'total' => $baseSalary
            ];
            $monthSalaryDetailModel->save($trainerMonthSalaryDetail);
            Db::commit();
            return $coreTrainerMonthSalaryModel;
        } catch (Exception|PDOException|ValidateException $e) {
            Db::rollback();
            $this->setError($e->getMessage());
            return false;
        } finally {
            Cache::delete($key);
        }
    }

    /**
     * 更改作废工资
     */
    public function updateCancel($recordId, $project, $cancel)
    {
        $salaryDetail = CoreTrainerMonthSalaryDetailModel::where([
            'recordId' => $recordId,
            'project' => $project
        ])->find();
        if (!$salaryDetail) {
            return true;
        }
        if ($salaryDetail['isCancel'] == $cancel) {
            return true;
        }
        $salaryDetail->isCancel = $cancel;
        // $res = CoreTrainerMonthSalaryDetailModel::where([
        //     'id' => $salaryDetail->id,
        //     'isCancel' => $salaryDetail['isCancel']
        // ])->update([
        //     'isCancel' => $cancel
        // ]);
        $res = $salaryDetail->save();
        if (!$res) {
            $this->setError('更改工资作废失败，请稍后重试');
            return false;
        }
        $month = $salaryDetail['month'];
        $trainerId = $salaryDetail['trainerId'];
        $coreTrainerMonthSalaryModel = new CoreTrainerMonthSalaryModel();
        $trainerMonthSalary = $coreTrainerMonthSalaryModel->getByTrainerAndMonth($trainerId, $month);
        if (!$trainerMonthSalary) {
            return true;
        }
        return $this->calculationSalary($trainerMonthSalary, $salaryDetail);
    }

    private function calculationSalary($trainerMonthSalary, $trainerMonthSalaryDetail)
    {
        $monthSalaryId = $trainerMonthSalary['id'];
        $project = $trainerMonthSalaryDetail['project'];
        $courseDeliveryType = $trainerMonthSalaryDetail['courseDeliveryType'];
        $isCancel = $trainerMonthSalaryDetail['isCancel'];
        $update = [];
        $totalAmount = $isCancel ?
            bcsub($trainerMonthSalary['totalAmount'], $trainerMonthSalaryDetail['total'], 2) :
            bcadd($trainerMonthSalary['totalAmount'], $trainerMonthSalaryDetail['total'], 2);
        $update['totalAmount'] = $totalAmount;

        $num = $trainerMonthSalaryDetail['num'];
        switch ($project) {
            case TrainerSalaryProjectEnum::C_30:
                $update['class30Num'] = $isCancel ?
                    bcsub($trainerMonthSalary['class30Num'], $num) :
                    bcadd($trainerMonthSalary['class30Num'], $num);
                break;
            case TrainerSalaryProjectEnum::C_60:
                $update['class60Num'] = $isCancel ?
                    bcsub($trainerMonthSalary['class60Num'], $num) :
                    bcadd($trainerMonthSalary['class60Num'], $num);
                break;
            case TrainerSalaryProjectEnum::EXPERIENCE:
                $update['classTrialNum'] = $isCancel ?
                    bcsub($trainerMonthSalary['classTrialNum'], $num) :
                    bcadd($trainerMonthSalary['classTrialNum'], $num);
                break;
            case TrainerSalaryProjectEnum::ANTI_FORGETTING:
                $update['antiNum'] = $isCancel ?
                    bcsub($trainerMonthSalary['antiNum'], $num) :
                    bcadd($trainerMonthSalary['antiNum'], $num);
                break;
        }

        if ($courseDeliveryType) {
            switch ($courseDeliveryType) {
                case CourseDeliveryTypeEnum::ONLINE:
                    $update['teachingOnlineNum'] = $isCancel ?
                        bcsub($trainerMonthSalary['teachingOnlineNum'], $num) :
                        bcadd($trainerMonthSalary['teachingOnlineNum'], $num);
                    break;
                case CourseDeliveryTypeEnum::ORGANIZATIONS:
                    $update['teachingOrganizationNum'] = $isCancel ?
                        bcsub($trainerMonthSalary['teachingOrganizationNum'], $num) :
                        bcadd($trainerMonthSalary['teachingOrganizationNum'], $num);
                    break;
                case CourseDeliveryTypeEnum::DOOR:
                    $update['teachingVisitNum'] = $isCancel ?
                        bcsub($trainerMonthSalary['teachingVisitNum'], $num) :
                        bcadd($trainerMonthSalary['teachingVisitNum'], $num);
                    break;
            }
        }

        $res = CoreTrainerMonthSalaryModel::update($update, ['id' => $monthSalaryId, 'totalAmount' => $trainerMonthSalary['totalAmount']]);
        if (!$res) {
            $this->setError('修改工资失败');
            return false;
        }
        return true;
    }

    /**
     * 处理薪资
     *
     * @param array $message 消息内容
     * @return void
     */
    public function handleSalary($message)
    {
        // 解析消息
        $messageClass = $message;
        $trainerId = $messageClass['trainerId'] ?? 0;
        $project = $messageClass['project'] ?? '';
        if ($project == TrainerSalaryProjectEnum::BASIC) {
            return;
        }

        $courseDeliveryType = $messageClass['courseDeliveryType'] ?? '';

        // 获取教师薪资信息
        $CoreTrainerSalaryModel = new CoreTrainerSalary();
        $trainerSalary = $CoreTrainerSalaryModel->where('trainerId', $trainerId)->find();
        if (empty($trainerSalary)) {
            return;
        }

        $recordId = $messageClass['recordId'] ?? '';

        // 创建月薪资记录
        $trainerMonthSalary = $this->createMonthSalary($trainerSalary);
        $monthSalaryId = $trainerMonthSalary['id'];
        $month = $trainerMonthSalary['month'];

        // 构建月薪资详情
        $trainerMonthSalaryDetail = [
            'trainerId' => $trainerId,
            'monthSalaryId' => $monthSalaryId,
            'month' => $month,
            'project' => $project,
            'courseDeliveryType' => $courseDeliveryType,
            'recordId' => $recordId,
            'isCancel' => 0 // false转换为0
        ];

        // 根据项目类型设置详情信息
        if ($project == TrainerSalaryProjectEnum::ANTI_FORGETTING) {
            $trainerMonthSalaryDetail['describe'] = (new TrainerSalaryProjectEnum())->getDescription($project);
            $trainerMonthSalaryDetail['num'] = 1;
            $trainerMonthSalaryDetail['price'] = $trainerSalary['antiSalary'] ?? 0;
            $trainerMonthSalaryDetail['total'] = $trainerSalary['antiSalary'] ?? 0;
        } else {
            $describe = (new TrainerSalaryProjectEnum())->getDescription($project) . "-" . (new CourseDeliveryTypeEnum())->getDescription($courseDeliveryType);
            $trainerMonthSalaryDetail['describe'] = $describe;
            $trainerMonthSalaryDetail['num'] = 1;

            switch ($project) {
                case TrainerSalaryProjectEnum::C_30:
                    $trainerMonthSalaryDetail['price'] = $trainerSalary['thirtySalary'] ?? 0;
                    $trainerMonthSalaryDetail['total'] = $trainerSalary['thirtySalary'] ?? 0;
                    break;
                case TrainerSalaryProjectEnum::C_60:
                    $trainerMonthSalaryDetail['price'] = $trainerSalary['sixtySalary'] ?? 0;
                    $trainerMonthSalaryDetail['total'] = $trainerSalary['sixtySalary'] ?? 0;
                    break;
                case TrainerSalaryProjectEnum::EXPERIENCE:
                    $trainerMonthSalaryDetail['price'] = $trainerSalary['practiceSalary'] ?? 0;
                    $trainerMonthSalaryDetail['total'] = $trainerSalary['practiceSalary'] ?? 0;
                    break;
            }
        }

        // 检查总金额是否大于0
        if (!isset($trainerMonthSalaryDetail['total']) || $trainerMonthSalaryDetail['total'] <= 0) {
            return;
        }

        // 保存数据
        $CoreTrainerMonthSalaryDetailModel = new CoreTrainerMonthSalaryDetailModel();
        $CoreTrainerMonthSalaryDetailModel->insert($trainerMonthSalaryDetail);

        // 统计数据
        $this->calculationSalary($trainerMonthSalary, $trainerMonthSalaryDetail);

    }

}